package com.eleme.dao.impl;


import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import com.eleme.dao.IBaseDao;
import com.eleme.dbutil.DbLink;
import com.eleme.entity.IEntityFactory;
import com.eleme.pubs.PublicFormats;

/** 
 * ClassName: BaseDao <br/> 
 * Function: Dao公共实现方法类 <br/> 
 * Reason: TODO ADD REASON(可选). <br/> 
 * date: 2017年12月19日 下午4:43:13 <br/> 
 * 
 * @author Pan 
 * @version @param <T> 
 * @since JDK 1.8 
 */  
public abstract class BaseDao<T> implements IBaseDao<T>, IEntityFactory<T> {

	protected final static Logger LOGGER = Logger.getLogger(BaseDao.class);
	protected Class<T> clazz = (Class <T>)(((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);

	
	/* (non-Javadoc)
	 * @see com.eleme.entity.IEntityFactory#createEntity(java.sql.ResultSet)
	 */
	public T createEntity(ResultSet rs) {
		List<T> li = createEntities(rs);
		return li.get(0);
	}


	/* (non-Javadoc)
	 * @see com.eleme.entity.IEntityFactory#createEntities(java.sql.ResultSet)
	 */
	public List<T> createEntities(ResultSet rs) {
		Class<T> mycls = clazz;
		List<T> li = new ArrayList<T>();
		T obj = null;
		try {
			obj = (T) mycls.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
			LOGGER.error("创建" + mycls.getName() + "对象失败：" + e.getMessage());
			return null;
		}
		
		Field[] fields = mycls.getDeclaredFields();
		
		try {
			while(rs != null && rs.next()) {
				obj = (T) mycls.newInstance();
				
				for(int i=0; i<fields.length;i++) {
					if(isFieldAccessable(fields[i]))
						fill(obj, rs.getObject(fields[i].getName()), fields[i]);
				}
				li.add(obj);
			}

		} catch(Exception e) {
			e.printStackTrace();
			LOGGER.error("根据ResultSet构造" + mycls.getName() + "对象失败：" + e.getMessage());
			return null;
		}
		
		return li;
	}

	
	

	public int insert(T entity) {
		PreparedStatement ps = null;
		int res = 0;
		boolean bFlag = false;
		Class<? extends Object> cls = entity.getClass();
		
		StringBuilder prefix = new StringBuilder(" Insert into ");
		StringBuilder suffix = new StringBuilder(" values(");
		try {
			prefix.append(cls.getSimpleName() + "(");
			Field[] fields = cls.getDeclaredFields();
			List<Object> params = new ArrayList<Object>();
			for(int i=0; i<fields.length; i++) {
				String fname = fields[i].getName();
				if(isFieldAccessable(fields[i])) {
					params.add(fetch(entity, fields[i]));
				}
				else
					continue;
				
				//如果找不到public的get方法或者是列表（属性名以lst开头则不保存）
				if(bFlag) {  //标记是不是第一个字段，如果是，前面不加逗号
					prefix.append(",");
					suffix.append(",");
				}else {
					bFlag = true;
				}
				prefix.append(fname);
				suffix.append("?");
			}
			
			prefix.append(")");
			suffix.append(")");
			prefix.append(suffix);
		
			LOGGER.debug("insert：" + prefix.toString());
			ps = getConnection().prepareStatement(prefix.toString());
			for(int i=0; i<params.size(); i++) {
				ps.setObject(i+1, params.get(i));
			}
			res = ps.executeUpdate();
		} catch (Exception e) {
			LOGGER.error(this.getClass().getSimpleName() + "类insert失败：" + prefix.toString() + "，错误信息：" + e.getMessage());
			e.printStackTrace();
		}
		
		return res;
	}

	

	public int delete(int id) {
		PreparedStatement ps = null;
		int res = 0;
		String tablename = clazz.getSimpleName();
		String sql = "delete from " + tablename + " where id = ?";
		try {
			LOGGER.debug("delete：" + sql);
			ps = getConnection().prepareStatement(sql);
			ps.setInt(1, id);
			res = ps.executeUpdate();
		} catch (SQLException e) {
			LOGGER.error("表" + tablename + "删除失败：" + sql + "，错误信息：" + e.getMessage());
			e.printStackTrace();
		}
		return res;
	}


	public int update(T entity, int id) {
		PreparedStatement ps = null;
		int res = 0;
		int i = 0;
		boolean bFlag = false;
		Class<? extends Object> cls = entity.getClass();
		
		StringBuilder prefix = new StringBuilder(" Update " + cls.getSimpleName() + " set ");
		try {
			Field[] fields = cls.getDeclaredFields();
			List<Object> params = new ArrayList<Object>();
			for(i=0; i<fields.length; i++) {
				String fname = fields[i].getName();
				if(isFieldAccessable(fields[i])) {
					params.add(fetch(entity, fields[i]));
				}
				else
					continue;

				if(bFlag) {
					prefix.append(",");
				}else
					bFlag = true;
				
				prefix.append(fname + " = ? ");
				
			}

			prefix.append(" Where id = ? ");
			LOGGER.debug("update：" + prefix.toString());
			ps = getConnection().prepareStatement(prefix.toString());
			for(i=0; i<params.size(); i++) {
				ps.setObject(i+1, params.get(i));
			}
			ps.setInt(i+1, id);
			res = ps.executeUpdate();
		} catch (Exception e) {
			LOGGER.error(this.getClass().getSimpleName() + "类update失败：" + prefix.toString() + "，错误信息：" + e.getMessage());
			e.printStackTrace();
		}
		
		return res;
	}


	public T getById(int id) {
		PreparedStatement ps = null;
		T obj = null;
		ResultSet res;
		String tablename = clazz.getSimpleName();
		String sql = "select * from " + tablename + " where id = ?";
		try {
			LOGGER.debug("getById：" + sql);
			ps = getConnection().prepareStatement(sql);
			ps.setInt(1, id);
			res = ps.executeQuery();
			if (res != null) 
			  obj = createEntity(res);
		} catch (SQLException e) {
			LOGGER.error("获取对象" + tablename + "失败：" + sql + "，错误信息：" + e.getMessage());
			e.printStackTrace();
		}
		return obj;
	}


	public List<T> getAll() {
		List<T> li = null;
		ResultSet res;
		String tablename = clazz.getSimpleName();
		String sql = "select * from " + tablename;
		try {
			LOGGER.debug("getAll：" + sql);
			res = getConnection().prepareStatement(sql).executeQuery();
			if (res != null) 
			  li = createEntities(res);
		} catch (SQLException e) {
			LOGGER.error("整表查询" + tablename + "失败：" + sql + "，错误信息：" + e.getMessage());
			e.printStackTrace();
		}
		return li;
	}


	/* (non-Javadoc)
	 * @see com.eleme.dao.IBaseDao#getConnection()
	 */
	public Connection getConnection() {
		return DbLink.getConnection();
	}
	
	

	/* (non-Javadoc)
	 * @see com.eleme.dao.IBaseDao#getStatment()
	 */
	public Statement getStatment() {
		Statement stm = null;
		try {
			stm = this.getConnection().createStatement();
		} catch (SQLException e) {
			LOGGER.error("创建statement对象错误！");
			e.printStackTrace();
		}
		return stm;
	}

	protected boolean isFieldAccessable(Field field) {
		Class type = field.getType();
		String fname = field.getName();
		//检查特殊字段名称
		if(fname.startsWith("lst")) //以lst开头字段不参与读写
			return false;
		//检查特殊类型
		if(type.isAssignableFrom(Collection.class)) 
			return false;
		else if(type.isAssignableFrom(Map.class))
			return false;
		
		return true;

	}
	
	protected void fill(Object bean, Object value, Field field) {
		Method method = null;
		String fname = field.getName();
		String methodname = "set" + fname.substring(0,  1).toUpperCase() + fname.substring(1);
		
		if(value == null) {
			if(field.getType() == int.class) {
				value = new Integer(0);
			}else if(field.getType() == float.class) {
				value = new Float(0);
			}else if(field.getType() == long.class) {
				value = new Long(0);
			}else if(field.getType() == double.class) {
				value = new Double(0);
			}else if(field.getType() == short.class) {
				value = new Short("0");
			}else if(field.getType()== String.class){
				value = "";
			}
		}

		try {
			method = bean.getClass().getMethod(methodname, field.getType());
			if(Modifier.isPublic(method.getModifiers()))
				method.invoke(bean, value);
		} catch (NoSuchMethodException e) {
			LOGGER.error(bean.getClass().getSimpleName() + "类的属性" + fname + "找不到setter");
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	
	}
	
	protected Object fetch(Object bean, Field field) {
		Method method = null;
		Object res = null;
		String fname = field.getName();
		String methodname = "get" + fname.substring(0,  1).toUpperCase() + fname.substring(1);
		
			try {
				method = bean.getClass().getMethod(methodname);
				if(Modifier.isPublic(method.getModifiers()))
					res = method.invoke(bean);
			} catch (NoSuchMethodException e) {
				LOGGER.error(bean.getClass().getSimpleName() + "类的属性" + fname + "找不到getter");
				e.printStackTrace();
			} catch (SecurityException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		return res;
	}
	
	protected String valueString(Object value) {
		String res;
		
		if (value.getClass() == String.class ) {
			res = quotedStr(value.toString());
		}else if(value.getClass() == Date.class){
			res = PublicFormats.FMTDATE.format((Date)value);
		}else {
			res = value.toString();
		}		
		return res;
	}
	
	public static String quotedStr(String str) {
		return "\"" + str + "\"";
	}	

	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}
